/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.demo.jackson.databinding;

import com.fasterxml.jackson.annotation.*;
import org.vacoor.nothing.common.json.Jacksons;

import java.util.Date;

/**
 * Jackson Core (Data-binding) Annotations
 */

/**
 * property auto-detect
 * 1. 定义!!没有使用Annotation!!的特定种类方法(getter,setter,creator)的自动检测机制
 * 1.5之前已经可以定义自动检测的一些method,field,creator的种类
 * eg: 可以通过SerializationConfig/DeserializationConfig来启用/禁用特定类型的method, field, creator的自动检测
 * 类似的也可以使用@JsonAutoDetect
 * 然而这只能允许启动和禁用自动检测,但是可见性是必须的并且不能改变(默认情况)
 * eg: getter, is-getter, creator, field 需要是public
 * setter 可以是任意可见行(包括private)
 * 这个功能的添加,使得可以明确定义最低可见性
 * 可以通过@JsonAutoDetect附加属性改变每个类(子类通过,mix-ins)的默认值
 *
 * @JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.DEFAULT)
 * // 如果getter 不是JsonAutoDetect.Visibility.NONE, setter将是任意可见行都可以,且设置无效
 * // 如果是NONE,此时setter才有效
 * <p/>
 * 全局默认值通过 objectMapper.setVisibilityChecker()重新设置
 * <p/>
 * 这个VisibilityChecker接口实际上是非常抽象的,它允许很多种类可见性的检测(包括不是基于java访问修饰符的)
 * 但是它的默认实现(VisibilityChecker.Std) 使用简单的基于访问修饰符(access-modifier-based)方式
 * <p/>
 * mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
 * //禁用所有
 * mapper.setVisibilityChecker(mapper.getVisibilityChecker.with(JsonAutoDetect.Visibility.NONE));
 */
@JsonAutoDetect(setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, getterVisibility = JsonAutoDetect.Visibility.DEFAULT)
/**
 * 2. 标识类在序列化和反序列化为json时 忽略的属性
 *      String[] value 指定逻辑属性名(即json property)
 *      boolean ignoreUnknown 定义在!!反序列化!!时是否忽略未知的json property
 */
@JsonIgnoreProperties(value = {"hibernateLazyInitializer", "age"}, ignoreUnknown = true)
@JsonPropertyOrder(value = {"id", "name", "age", "birthday"})
public class User {
    /**
     * 3.(method/field)在serialization/deserialization时忽略该field/property,即使被自动检测或使用其他annotation
     */
    @JsonIgnore
    private long id;
    /**
     * 4. @JsonUnwrapped 标注的property在序列化/反序列化将直接以当前类的json property属性出现而不是包装为对象后出现
     * <pre>
     *    eg: {
     *          "name" : {
     *              "first": "first",
     *              "last": "last"
     *              }
     *        }
     *        使用该注解
     *        {
     *            "first": "first",
     *            "last": "last"
     *        }
     * </pre>
     * 其中prefix指定前缀, suffix指定后缀, enabled是否启用
     */
    @JsonUnwrapped(prefix = "prefix.", suffix = ".suffix", enabled = true)
    @JsonManagedReference
    private Name name;

    /*
    @JsonSerialize(using = DateSerializer.class)
    @JsonDeserialize(using = DateDeserializer.class)
    */
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy年MM月dd日 HH时mm分ss秒", timezone = "GMT+8")
    /**
     * 5. 当标注在getter上表示序列化时json property的名称
     *    当标注在setter上表示反序列化时json property的名称
     *    当应用在非静态成员field表示序列化/反序列化时json property的名称
     *    同一个property的getter/setter对 @JsonProperty必须一样(如果定义名称为property则认为没有定义,按照另外一个计算)
     * 注意:
     *      使用@JsonProperty 对于省略value时,
     *          void setSize(int ) <==> void size(int)  --> json property = size
     *          int getSize() <==> int size() --> json property = size
     *          String FirstName  --> json property = FirstName
     *          //自动检测,则需要检测getter/setter
     */
    @JsonProperty("birthday")
    private Date birth;
    private int age;
    private String addr;

    @JsonProperty("p")
    private User parent;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Name getName() {
        return name;
    }

    public void setName(Name name) {
        this.name = name;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public User getParent() {
        return parent;
    }

    public void setParent(User parent) {
        this.parent = parent;
    }

    //
    public static class Name {
        @JsonBackReference
        private String first;
        private String last;
        private boolean deleted;

        public String getFirst() {
            return first;
        }

        public void setFirst(String first) {
            this.first = first;
        }

        public String getLast() {
            return last;
        }

        public void setLast(String last) {
            this.last = last;
        }

        @JsonFormat(shape = JsonFormat.Shape.NUMBER)
        public Boolean getDeleted() {
            return deleted;
        }

        public void setDeleted(Boolean deleted) {
            this.deleted = deleted;
        }
    }

    public static void main(String[] args) {
        System.out.println(Jacksons.serialize(new Name()));
    }
}
